#define  _CRT_SECURE_NO_WARNINGS
#include "pagecache.h"
PageCache PageCache::_sInst;
span* PageCache::newspan(size_t k)
{
	assert(k > 0);
	if (k > npages - 1)//，太大了，pagecache中最大的span都放不下了，就直接向系统的对申请空间
	{
		void* ptr = SystemAlloc(k);
		span* sp = spanpool.New(); 
		sp->_n = k;
		sp->_pageid = (Page_ID)ptr >> page_shift;
		_id_span_map[sp->_pageid] = sp;
		return sp;
	}
	else //   (npages-1)<<page_shift  >=  size  >   max_size,这么大的内存不适用中间的threadcache和spancache，而是直接受用pagecache中的spanlist桶
	{
		if (!_pagespanlistarray[k].empty())//检查span页数为k的pagespanlist里面是否有不为空的span
		{
			span* sp = _pagespanlistarray[k].popfront();
			for (Page_ID i = 0; i < sp->_n; i++)
				_id_span_map[sp->_pageid + i] = sp;
			return sp;//从pagespanlist中移除并弹出
		}
		//该桶为空，检查后面的桶有没有span，如果有将该span切分
		for (size_t i = k + 1; i < npages; i++)
		{
			if (!_pagespanlistarray[i].empty())
			{
				span* ispan = _pagespanlistarray[i].popfront();
				span* kspan = spanpool.New();
				kspan->_pageid = ispan->_pageid;
				kspan->_n = k;//////////////////////////span没有入spanlist
				ispan->_pageid += k;
				ispan->_n -= k;
				_pagespanlistarray[ispan->_n].pushfront(ispan);

				//存储ispan首页和尾页页号跟ispan映射，方便page cache回收内存时进行查找合并
				_id_span_map[ispan->_pageid] = ispan;
				_id_span_map[ispan->_pageid + ispan->_n - 1] = ispan;

				for (Page_ID i = 0; i < kspan->_n; i++)//建立id和span的映射，方便通过找该内存所在的内存页进而找到它对应的span
					_id_span_map[kspan->_pageid + i] = kspan;
				return kspan;
			}
		}
		//后面的所有桶都是空的，找堆要一个128页的span
		span* biggestspan = spanpool.New();
		void* ptr = SystemAlloc(npages - 1);
		biggestspan->_pageid = (Page_ID)ptr >> page_shift;
		biggestspan->_n = npages - 1;
		_pagespanlistarray[biggestspan->_n].pushfront(biggestspan);
		return newspan(k);
	}
}
span* PageCache::map_obj_to_span(void* obj)
{
	std::unique_lock<std::mutex> lock(_pagemtx);
	//Page_ID page = (Page_ID)obj >> page_shift;
	/*auto ret = _id_span_map.find(page);
	if (ret != _id_span_map.end())
		return ret->second;
	else assert(false) return nullptr; */
	Page_ID id = ((Page_ID)obj >> page_shift);
	auto ret = _id_span_map.find(id);
	assert(ret != _id_span_map.end());
	return ret->second;
}

//对span前后页，尝试进行合并，缓解外内存碎片问题
void PageCache::Realse_span_to_page(span* sp)
{
	if (sp->_n > npages-1)//不是从PageCache中申请出来的空间，是直接从堆中申请出的大空间(大于128页)
	{
		void* ptr = (void*)(sp->_pageid << page_shift);
		SystemFree(ptr);
		spanpool.Delete(sp);
		return;
	}
	while (1)//向前合并
	{
		Page_ID previd = sp->_pageid - 1;
		auto ret = _id_span_map.find(previd);
		if (ret == _id_span_map.end()) break;
		span* prevspan = ret->second;
		if (prevspan->_isused || prevspan->_n + sp->_n > npages - 1) break;///
		sp->_pageid = prevspan->_pageid;
		sp->_n += prevspan->_n;
		_pagespanlistarray[prevspan->_n].Erase(prevspan);
		spanpool.Delete(prevspan);
	}
	while (1)//向后合并
	{
		Page_ID nextid = sp->_pageid + sp->_n;
		auto ret = _id_span_map.find(nextid);
		if (ret == _id_span_map.end()) break;
		span* nextspan = ret->second;
		if (nextspan->_isused || nextspan->_n + sp->_n > npages - 1) break;/////////
		sp->_n += nextspan->_n;
		_pagespanlistarray[nextspan->_n].Erase(nextspan);
		spanpool.Delete(nextspan);
	}
	_pagespanlistarray[sp->_n].pushfront(sp);
	sp->_isused = false;
	_id_span_map[sp->_pageid] = sp;
	_id_span_map[sp->_pageid + sp->_n - 1] = sp;
}